/* Gauge - Performance Measurement Framework for Mobile Platforms
 * Copyright (C) 2013, Juha Hytonen <juha.a.hytonen@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.gauge;

/**
 * Base class for all benchmarks.
 * 
 * Implement a benchmark by subclassing this class and implementing the abstract
 * methods. Also remember to add your benchmark to the relevant BenchmarkFactory.
 * 
 * A benchmark consists of three phases:
 * 1) In the SETUP phase you start all probes and background workloads.
 *    You can also override default settings for log and measurement storage.
 * 2) In the RUN phase you should run your periodic and timed workloads.
 * 3) In the optional TEARDOWN phase you can perform any necessary cleanup.
 *    Please note that all probes and workloads are stopped automatically.
 * 
 * @see BenchmarkController
 * @see org.gauge.GaugeAgent.BenchmarkFactory
 */
public abstract class Benchmark {
	
	private BenchmarkController controller;
	
	public final void SetController(BenchmarkController controller) {
		this.controller = controller;
	}
	
	/**
	 * You should return a descriptive, human-readable name for your benchmark.
	 */
	public String GetName() {
		return "UNNAMED";
	}
	
	/**
	 * You should start all probes and background workloads here.
	 * You can also override default settings for log and measurement storage.
	 * 
	 * @see readProbe
	 * @see readProbeEvery
	 * @see useDefaultMeasurementStorage
	 * @see useThisMeasurementStorage
	 * @see useDefaultLog
	 * @see useThisLog
	 */
	public abstract void Setup();
	
	/**
	 * Use default measurement storage provided by the framework. This is usually
	 * the remote storage on the server.
	 */
	protected final void useDefaultMeasurementStorage() {
		// Intentionally empty.
	}
	
	/**
	 * Use given measurement storage to store measurements made during benchmarks.
	 */
	protected final void useThisMeasurementStorage(Class<? extends MeasurementStorage> storageClass) {
		try {
			MeasurementStorage storage = storageClass.newInstance();
			MeasurementStorage.Register(storage);
		}
		catch(Exception e) {
		}
	}
	
	/**
	 * Use default benchmark execution log provided by the framework. This is
	 * usually the remote log on the server.
	 */
	protected final void useDefaultLog() {
		// Intentionally empty.
	}
	
	/**
	 * Use given log for the benchmark execution log.
	 */
	protected final void useThisLog(Class<? extends Log> logClass) {
		try {
			Log log = logClass.newInstance();
			Log.Register(log);
		}
		catch(Exception e) {
		}
	}

	/**
	 * Read given probe once. Use for static probes.
	 * 
	 * @see Probe
	 * @see Probe.Type
	 */
	protected final void readProbe(Class<? extends Probe> probeClass) {
		controller.ReadProbe(probeClass);
	}

	/**
	 * Read given probe on given intervals. Interval is given in milliseconds.
	 * Use for dynamic probes.
	 * 
	 * @see Probe
	 * @see Probe.Type
	 */
	protected final void readProbeEvery(Class<? extends Probe> probeClass, int millisecs) {
		controller.ReadProbeEvery(probeClass, millisecs);
	}
	
	/**
	 * Runs a background workload. This background is run during the whole execution
	 * of the benchmark (unless it stops by itself).
	 *
	 * @see Workload
	 */
	protected final void runWorkload(Class<? extends Workload> workloadClass) {
		controller.RunWorkload(workloadClass);
	}
	
	/**
	 * You should run your periodic and timed workloads here.
	 * 
	 * @see runWorkloadFor
	 * @see runWorkloadEvery
	 * @see stopRunningWorkload
	 * @see beforeNextActionWaitFor
	 */
	public abstract void Run();
	
	/**
	 * Runs given workload for given number of milliseconds. Workload is terminated
	 * after the given time.
	 * 
	 * @see Workload
	 */
	protected final void runWorkloadFor(Class<? extends Workload> workloadClass, int millisecs) {
		controller.RunWorkloadFor(workloadClass, millisecs);
	}
	
	/**
	 * Runs given workload on given intervals. Workload is terminated in between runs.
	 * 
	 * @see Workload
	 */
	protected final void runWorkloadEvery(Class<? extends Workload> workloadClass, int millisecs) {
		controller.RunWorkloadEvery(workloadClass, millisecs);
	}
	
	/**
	 * Waits given number of milliseconds before next action is executed. Use this
	 * to control when workloads are started in your benchmark.
	 */
	protected final void beforeNextActionWaitFor(int millisecs) {
		controller.BeforeNextActionWaitFor(millisecs);
	}
	
	/**
	 * You can perform any necessary cleanup here.
	 */
	public void Teardown() {
	}
	
	/** 
	 * Waits for given workload to stop. Works only for background workloads.
	 * 
	 * Please note that the total amount waited is regulated and may be shorter
	 * than the duration of your workload.
	 * 
	 * @see Workload
	 */
    protected final void waitForWorkloadToStop(Class<? extends Workload> workloadClass) {
    	controller.WaitForWorkloadToStop(workloadClass);
    }
	
	/** 
	 * Stops running given workload. Works only for background workloads.
	 * 
	 * @see Workload
	 */
	protected final void stopRunningWorkload(Class<? extends Workload> workloadClass) {
		controller.StopRunningWorkload(workloadClass);
	}
	
}
